﻿using Microsoft.VisualBasic.FileIO;
using RQX.Common.Core.Extension;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace RQX.Common.Core.File
{
    /// <summary>
    /// 文件操作工具类
    /// </summary>
    public class FileUtils
    {
        private static object lockObj = new object();
        #region File
        #region CheckOrCreate
        /// <summary>
        /// 检查文件是否存在，不存在则创建
        /// </summary>
        /// <param name="filePath"></param>
        public static void CheckOrCreatePath(string filePath)
        {
            FileInfo fileInfo = new FileInfo(filePath);
            var dirPath = fileInfo.DirectoryName;
            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            if (!fileInfo.Exists)
            {
                lock (lockObj)
                {
                    if (!fileInfo.Exists)
                    {
                         using var fs = fileInfo.Create();
                    }
                }
            }
        }
        /// <summary>
        /// 创建新的文件，若原文件存在，则删除原文件
        /// </summary>
        /// <param name="filePath"></param>
        public static void CreateNewFile(string filePath)
        {
            FileInfo fileInfo = new FileInfo(filePath);
            var dirPath = fileInfo.DirectoryName;
            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
            using (fileInfo.Create()) { }
        }
        #endregion
        #region Save
        /// <summary>
        /// 保存所有内容到文件，覆盖保存
        /// </summary>
        /// <param name="fileFullPath"></param>
        /// <param name="msg"></param>
        public static void SaveAllToFile(string fileFullPath, string msg) => SaveToFile(fileFullPath, msg, false);
        /// <summary>
        /// 保存内容到文件，追加
        /// </summary>
        /// <param name="fileFullPath"></param>
        /// <param name="msg"></param>
        public static void SaveAppendToFile(string fileFullPath, string msg) => SaveToFile(fileFullPath, msg, true);
        #endregion
        #region Get
        /// <summary>
        /// 获取目录下的文件
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="isGetAll"></param>
        /// <returns></returns>
        public static List<FileInfo> GetFiles(string dirPath)=> GetFiles(dirPath, false);
        /// <summary>
        /// 获取目录下，继承了接口类型的文件，用于搜索指定插件
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="baseInterface"></param>
        /// <returns></returns>
        public static List<FileInfo> GetFiles(string dirPath, Type baseInterface)
        {
            var fileList = GetFiles(dirPath, false);
            return GetFiles(fileList, baseInterface);
        }
        /// <summary>
        /// 获取目录下所有的文件，递归查询
        /// </summary>
        /// <param name="dirPath"></param>
        /// <returns></returns>
        public static List<FileInfo> GetAllFiles(string dirPath)=> GetFiles(dirPath, true);
        /// <summary>
        /// 获取目录下，继承了接口类型的所有文件，用于搜索指定插件
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="baseInterface"></param>
        /// <returns></returns>
        public static List<FileInfo> GetAllFiles(string dirPath, Type baseInterface)
        {
            var fileList = GetFiles(dirPath, true);
            return GetFiles(fileList, baseInterface);
        }
        #endregion
        #endregion
        #region Dir
        /// <summary>
        /// 检查并创建dir目录
        /// </summary>
        /// <param name="dirPath"></param>
        public static void CheckOrCreateDirPath(string dirPath)
        {
            if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
        }
        /// <summary>
        /// 删除目录，并删除目录下的所有内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="isRelative"></param>
        public static void DeletePath(string path, bool isRelative = false)
        {
            if (isRelative)
            {
                path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
            }
            Directory.Delete(path, true);
        }
        #endregion
        #region private
        /// <summary>
        /// 从文件列表中，找出继承了基类类型的文件
        /// </summary>
        /// <param name="fileList"></param>
        /// <param name="baseInterface"></param>
        /// <returns></returns>
        private static List<FileInfo> GetFiles(List<FileInfo> fileList,Type baseInterface)
        {
            List<FileInfo> resultList = new List<FileInfo>();
            fileList.ForEach(file =>
            {
                try
                {
                    var typeList = Assembly.LoadFrom(file.FullName).GetTypes();
                    foreach (var type in typeList)
                    {
                        if (!type.IsAbstract && type.IsPublic && baseInterface.IsAssignableFrom(type))
                        {
                            resultList.Add(file);
                            break;
                        }
                    }
                }
                catch { }
            });
            return resultList;
        }

        /// <summary>
        /// 保存内容到文件
        /// </summary>
        /// <param name="fileFullPath"></param>
        /// <param name="msg"></param>
        /// <param name="isAppend"></param>
        private static void SaveToFile(string fileFullPath, string msg, bool isAppend)
        {
            CheckOrCreatePath(fileFullPath);
            using StreamWriter sw = new StreamWriter(fileFullPath, isAppend);
            sw.Write(msg);
            sw.Flush();
        }
        /// <summary>
        /// 获取目录下的文件
        /// </summary>
        /// <param name="dirPath"></param>
        /// <param name="isAll">是否递归查询</param>
        /// <returns></returns>
        private static List<FileInfo> GetFiles(string dirPath,bool isAll)
        {
            List<FileInfo> list = new List<FileInfo>();
            CheckOrCreateDirPath(dirPath);
            var files = Directory.GetFiles(dirPath);
            files.ForEach(file => list.Add(new FileInfo(file)));
            if (isAll)
            {
                var dirs = Directory.GetDirectories(dirPath);
                dirs.ForEach(dir => list.AddRange(GetFiles(dir, isAll)));
            }
            return list;
        }

        #endregion
    }
}
